﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;

using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;


using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;

using System.Text;

using System.Diagnostics;
using System.Diagnostics.Eventing;


namespace ProtocolWorkflows.InboundDocumentslWF
{
    public sealed partial class InboundDocumentslWF : StateMachineWorkflowActivity
    {


        #region  properties


        public string taskContentTypeId = "0x01080100FFbc98c2529347a5886b8d2576b954e2";

        public bool isTaskFinished = false;
        public bool isWorkflowFinished = false;
        public bool sendBackToRouter = false;


        public string currentTaskLogin = "";
        public string prevTaskLogin = "";


        #endregion




        public InboundDocumentslWF()
        {
            InitializeComponent();
        }

        public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();

        public Guid createRouterTask_TaskId1 = default(System.Guid);
        public SPWorkflowTaskProperties createRouterTask_TaskProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        private void createRouterTask_Invoked(object sender, EventArgs e)
        {

            string username = null;

            try
            {
                username = GetRouter(this.workflowProperties.Item);
            }
            catch (Exception codeException)
            {
                WriteError(codeException);
            }




            string subject = "";
            string body = "";

            SetMailSubjectAndBody("INCOMING_DOCUMENT_NOTIFY_ROUTER", this.workflowProperties.Item, ref  subject, ref   body);

            SendEmail("INCOMING_DOCUMENT_NOTIFY_ROUTER", this.workflowProperties.Item, username, subject, body);



            createRouterTask_TaskId1 = Guid.NewGuid();
            createRouterTask_TaskProperties1.Title = subject;
            //createRouterTask_TaskProperties1.Description = Resource1.RouterTask_TaskDescription;

            // Add the custom properties
            createRouterTask_TaskProperties1.ExtendedProperties["TaskStage"] = "router";
            createRouterTask_TaskProperties1.ExtendedProperties["TargetListItemId"] = this.workflowProperties.Item.ID.ToString();
            createRouterTask_TaskProperties1.ExtendedProperties["TargetListId"] = this.workflowProperties.Item.ParentList.ID.ToString();

            createRouterTask_TaskProperties1.ExtendedProperties["LinkToItem"] = string.Format("{0}/{1}", this.workflowProperties.Web.Url, this.workflowProperties.Item.Url);


            createRouterTask_TaskProperties1.AssignedTo = username;






        }


        public SPWorkflowTaskProperties onTaskChanged1_AfterProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChanged1_BeforeProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        private void onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e)
        {


            onTaskChanged1_BeforeProperties1 = onTaskChanged1.BeforeProperties;
            onTaskChanged1_AfterProperties1 = onTaskChanged1.AfterProperties;



        }

        private void IsRouterTaskComplete(object sender, ConditionalEventArgs e)
        {
            if (onTaskChanged1_AfterProperties1.PercentComplete == 1F)
                e.Result = true;
            else
                e.Result = false;

        }



        private void IsApproverTaskCompleted(object sender, ConditionalEventArgs e)
        {
            try
            {
                if (onTaskChanged2_AfterProperties1.PercentComplete == 1F)
                {

                    e.Result = true;

                }
            }
            catch
            {
                e.Result = false;
            }
        }

        private void IsApproverTaskReturned(object sender, ConditionalEventArgs e)
        {
            try
            {

                if (onTaskChanged2_AfterProperties1.PercentComplete == 1F)
                {
                    string outcome = (string)onTaskChanged2_AfterProperties1.ExtendedProperties[this.workflowProperties.TaskList.Fields["TaskOutcome"].Id];

                    if (outcome.Contains(Resource1.Status_Returned))
                        e.Result = true;
                    else
                        e.Result = false;
                }
            }
            catch
            {
                e.Result = false;
            }
        }


        private void IsReviewerTaskCompleted(object sender, ConditionalEventArgs e)
        {
            try
            {
                if (onTaskChanged3_AfterProperties1.PercentComplete == 1F)
                {

                    string outcome = (string)onTaskChanged3_AfterProperties1.ExtendedProperties[this.workflowProperties.TaskList.Fields["TaskOutcome"].Id];

                    if (outcome.Contains(Resource1.Status_Complete))
                        e.Result = true;
                    else
                        e.Result = false;
                }
            }
            catch
            {
                e.Result = false;
            }
        }

        private void IsReviewerReturned(object sender, ConditionalEventArgs e)
        {
            try
            {
                if (onTaskChanged3_AfterProperties1.PercentComplete == 1F)
                {


                    string outcome = (string)onTaskChanged3_AfterProperties1.ExtendedProperties[this.workflowProperties.TaskList.Fields["TaskOutcome"].Id];

                    if (outcome.Contains(Resource1.Status_Returned))
                        e.Result = true;
                    else
                        e.Result = false;
                }
            }
            catch
            {
                e.Result = false;
            }
        }






        public Guid createApproverTask_TaskId1 = default(System.Guid);
        public SPWorkflowTaskProperties createApproverTask_TaskProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();


        private void createApproverTask_Invoking(object sender, EventArgs e)
        {

            string approver = null;

            // If task has been sent back - then reassign to same user
            if (!string.IsNullOrEmpty(this.prevTaskLogin))
            {
                approver = this.prevTaskLogin;
            }
            else
            {

                try
                {
                    approver = GetDeptApprover(this.workflowProperties.Item);
                }
                catch (Exception codeException)
                {
                    WriteError(codeException);
                }


            }
            createApproverTask_TaskId1 = Guid.NewGuid();

            createApproverTask_TaskProperties1.Title = Resource1.ManagerTask_TaskTitle;
            createApproverTask_TaskProperties1.Description = Resource1.ManagerTask_TaskDescription;

            // Add the custom properties
            createApproverTask_TaskProperties1.ExtendedProperties["TaskStage"] = "approver";
            createApproverTask_TaskProperties1.ExtendedProperties["TargetListItemId"] = this.workflowProperties.Item.ID.ToString();
            createApproverTask_TaskProperties1.ExtendedProperties["TargetListId"] = this.workflowProperties.Item.ParentList.ID.ToString();

            createApproverTask_TaskProperties1.ExtendedProperties["LinkToItem"] = string.Format("{0}/{1}", this.workflowProperties.Web.Url, this.workflowProperties.Item.Url);

            if (approver != null)
            {
                createApproverTask_TaskProperties1.AssignedTo = approver;


                this.currentTaskLogin = approver;
                this.prevTaskLogin = "";
            }

        }


        private void IsApproverTaskComplete(object sender, ConditionalEventArgs e)
        {
            if (onTaskChanged2_AfterProperties1.PercentComplete == 1F)
                e.Result = true;
            else
                e.Result = false;

        }





        private void IsReviewerTaskComplete(object sender, ConditionalEventArgs e)
        {
            if (onTaskChanged3_AfterProperties1.PercentComplete == 1F)
                e.Result = true;
            else
                e.Result = false;

        }





        public SPWorkflowTaskProperties onTaskChanged2_AfterProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChanged2_BeforeProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();




        public Guid createReviewTask_TaskId1 = default(System.Guid);
        public SPWorkflowTaskProperties createReviewTask_TaskProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        private void createReviewTask_Invoked(object sender, EventArgs e)
        {

            string reviewer = null;

            try
            {
                reviewer = GetDeptManager(this.workflowProperties.Item);
            }
            catch (Exception codeException)
            {
                WriteError(codeException);
            }



            string subject = "";
            string body = "";

            SetMailSubjectAndBody("INCOMING_DOCUMENT_APPROVAL_TASK", this.workflowProperties.Item, ref  subject, ref   body);

            SendEmail("INCOMING_DOCUMENT_APPROVAL_TASK", this.workflowProperties.Item, reviewer, subject, body);




            createReviewTask_TaskId1 = Guid.NewGuid();

            createReviewTask_TaskProperties1.Title = subject;
            // createReviewTask_TaskProperties1.Description = Resource1.ManagerTask_TaskDescription;

            // Add the custom properties
            createReviewTask_TaskProperties1.ExtendedProperties["TaskStage"] = "review";
            createReviewTask_TaskProperties1.ExtendedProperties["TargetListItemId"] = this.workflowProperties.Item.ID.ToString();
            createReviewTask_TaskProperties1.ExtendedProperties["TargetListId"] = this.workflowProperties.Item.ParentList.ID.ToString();

            createReviewTask_TaskProperties1.ExtendedProperties["LinkToItem"] = string.Format("{0}/{1}", this.workflowProperties.Web.Url, this.workflowProperties.Item.Url);

            if (reviewer != null)
            {
                createReviewTask_TaskProperties1.AssignedTo = reviewer;


                this.prevTaskLogin = this.currentTaskLogin;
                this.currentTaskLogin = reviewer;

            }



        }

        public SPWorkflowTaskProperties onTaskChanged3_AfterProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChanged3_BeforeProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        private void onTaskChanged3_Invoked(object sender, ExternalDataEventArgs e)
        {

            onTaskChanged3_BeforeProperties1 = onTaskChanged3.BeforeProperties;
            onTaskChanged3_AfterProperties1 = onTaskChanged3.AfterProperties;

        }






        #region Supporting methods



        private void GetEmailSettings(SPListItem item, ref bool isEnabled)
        {

            SPList configList = item.Web.GetList(string.Format("{0}/Lists/{1}", item.Web.ServerRelativeUrl, "LibraryConfiguration"));

            foreach (SPListItem configItem in configList.Items)
            {
                if (configItem[configItem.ParentList.Fields.GetFieldByInternalName("ListName").Id].ToString() == item.ParentList.Title)
                {
                    if (configItem[configItem.ParentList.Fields.GetFieldByInternalName("EmailEnabled").Id] != null)
                    {

                        try
                        {
                            isEnabled = (bool)configItem[configItem.ParentList.Fields.GetFieldByInternalName("EmailEnabled").Id];
                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }
                    }
                    break;
                }

            }

        }

        private string GetRouter(SPListItem item)
        {

            string user = null;

            SPList configList = item.Web.GetList(string.Format("{0}/Lists/{1}", item.Web.ServerRelativeUrl, "LibraryConfiguration"));

            foreach (SPListItem configItem in configList.Items)
            {

                if (configItem["ListName"].ToString() == item.ParentList.Title)
                {
                    if (configItem["Router"] != null)
                    {

                        try
                        {
                            user = GetLoginName(configItem, "Router");
                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }
                    }
                    break;
                }

            }

            return user;
        }

        private string GetDeptApprover(SPListItem item)
        {

            //SPUser user = null;
            string user = null;

            int deptId = GetLookupPropertyId(item, "OwnerDepartment");


            SPList deptsList = item.Web.GetList(string.Format("{0}/Lists/{1}", item.Web.ServerRelativeUrl, "Departments"));


            SPListItem dept = deptsList.GetItemById(deptId);

            if (dept[dept.ParentList.Fields.GetFieldByInternalName("DocumentApprovers").Id] != null)
            {
                try
                {
                    user = GetLoginName(dept, "DocumentApprovers");
                }
                catch (Exception codeException)
                {
                    WriteError(codeException);
                }

            }

            return user;
        }

        private string GetDeptManager(SPListItem item)
        {

            //SPUser user = null;
            string user = null;


            int deptId = GetLookupPropertyId(item, "OwnerDepartment");



            SPList deptsList = item.Web.GetList(string.Format("{0}/Lists/{1}", item.Web.ServerRelativeUrl, "Departments"));


            SPListItem dept = deptsList.GetItemById(deptId);



            if (dept[dept.ParentList.Fields.GetFieldByInternalName("DepartmentManagers").Id] != null)
            {

                try
                {
                    user = GetLoginName(dept, "DepartmentManagers");
                }
                catch (Exception codeException)
                {
                    WriteError(codeException);
                }

            }

            return user;
        }



        private string GetLoginName(SPListItem item, string columnName)
        {

            string loginName = "";

            var userValue = new SPFieldUserValue(item.Web, (string)item[columnName]);

            if (userValue != null && userValue.User != null)
            {
                loginName = userValue.User.LoginName;
            }
            else
            {
                SPGroup group = item.Web.Groups[userValue.LookupValue];

                if (group != null)
                    loginName = group.LoginName;
            }

            return loginName;
        }



        private void SendEmail(string messageCode, SPListItem item, string toLogin, string subject, string body)
        {

            string to = "";

            SPUser toUser = null;

            try
            {

                toUser = item.Web.AllUsers[toLogin];


                if (toUser != null)
                {

                    bool isEnabled = false;

                    GetEmailSettings(item, ref isEnabled);

                    if (isEnabled)
                    {


                        to = toUser.Email;

                        try
                        {
                            SPUtility.SendEmail(item.Web, true, true, to, subject, body);
                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }

                    }


                }


            }
            catch (Exception codeException)
            {
                WriteError(codeException);
            }



        }

        private void SetMailSubjectAndBody(string messageCode, SPListItem item, ref string subject, ref string body)
        {



            try
            {
                SPList messagesList = item.Web.GetList(string.Format("{0}/Lists/{1}", item.Web.ServerRelativeUrl, "MailMessages"));


                StringBuilder queryCommand = new StringBuilder();

                queryCommand.Append("<Where>");
                queryCommand.Append("<Eq>");
                queryCommand.Append("<FieldRef Name=\"MessageCode\" />");
                queryCommand.Append(string.Format("<Value Type=\"Text\">{0}</Value>", messageCode));
                queryCommand.Append("</Eq>");
                queryCommand.Append("</Where>");

                SPQuery query = new SPQuery();
                query.Query = queryCommand.ToString();


                SPListItemCollection messages = messagesList.GetItems(query);

                if (messages != null && messages.Count > 0)
                {

                    SPListItem message = messages[0];

                    if (message[message.ParentList.Fields.GetFieldByInternalName("MessageSubject").Id] != null)
                    {
                        try
                        {
                            subject = message[message.ParentList.Fields.GetFieldByInternalName("MessageSubject").Id].ToString();

                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }

                    }


                    if (message[message.ParentList.Fields.GetFieldByInternalName("MessageBodyText").Id] != null)
                    {
                        try
                        {
                            body = message[message.ParentList.Fields.GetFieldByInternalName("MessageBodyText").Id].ToString();



                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }

                    }



                    if (!string.IsNullOrEmpty(subject))
                    {
                        try
                        {
                            subject = string.Format(subject, item.Title);
                        }
                        catch { ;}

                    }


                    if (!string.IsNullOrEmpty(body))
                    {
                        try
                        {
                            body = string.Format(body, item.Title);
                        }
                        catch { ;}

                    }


                }

            }
            catch (Exception codeException)
            {
                WriteError(codeException);
            }



        }



        private void WriteError(Exception ex)
        {

            EventLog LogToSystem = new EventLog();

            LogToSystem.Source = "SharePoint 2010 Protocols Library";
            LogToSystem.WriteEntry(ex.Message + " : " + ex.StackTrace, EventLogEntryType.Error);

        }



        private string GetLookupPropertyValue(SPListItem item, string fieldName)
        {
            string value = "";

            try
            {




                if (item[item.ParentList.Fields.GetFieldByInternalName(fieldName).Id] != null)
                {
                    string lookupFieldValue = (string)item[item.ParentList.Fields.GetFieldByInternalName(fieldName).Id];

                    if (lookupFieldValue.Length > 0)
                    {
                        value = lookupFieldValue.Substring(lookupFieldValue.IndexOf("#") + 3);
                    }
                }
            }
            catch (Exception codeException)
            {
                WriteError(codeException);
            }

            return value;
        }

        private int GetLookupPropertyId(SPListItem item, string fielName)
        {
            int id = 0;

            try
            {




                if (item[item.ParentList.Fields.GetFieldByInternalName(fielName).Id] != null)
                {
                    string lookupFieldValue = (string)item[item.ParentList.Fields.GetFieldByInternalName(fielName).Id];

                    if (lookupFieldValue.Length > 0)
                    {
                        string tmpValue = lookupFieldValue.Substring(0, lookupFieldValue.IndexOf("#") - 1);

                        if (!string.IsNullOrEmpty(tmpValue))
                            id = int.Parse(tmpValue);
                    }
                }
            }
            catch (Exception codeException)
            {
                WriteError(codeException);
            }

            return id;
        }


        #endregion

        private void FinalUpdateToItem_ExecuteCode(object sender, EventArgs e)
        {

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                try
                {
                    using (SPSite site = new SPSite(this.workflowProperties.Item.Web.Url))
                    {
                        site.AllowUnsafeUpdates = true;

                        using (SPWeb web = site.OpenWeb())
                        {

                            web.AllowUnsafeUpdates = true;


                            SPListItem item = web.Lists[this.workflowProperties.Item.ParentList.ID].GetItemById(this.workflowProperties.Item.ID);

                            #region Update the item

                            SPFieldBoolean isClosedField = (SPFieldBoolean)this.workflowProperties.Web.Fields.GetFieldByInternalName("IsClosed");
                            item[isClosedField.Title] = true;


                            SPFieldDateTime dateClosedField = (SPFieldDateTime)this.workflowProperties.Web.Fields.GetFieldByInternalName("CloseDate");
                            item[dateClosedField.Title] = DateTime.Now;


                            SPFieldChoice statusField = (SPFieldChoice)this.workflowProperties.Web.Fields.GetFieldByInternalName("DocumentStatus");
                            item[statusField.Title] = Resource1.Status_Complete;


                            #endregion

                            item.SystemUpdate();

                        }
                    }
                }
                catch (Exception codeException)
                {
                    WriteError(codeException);
                }
            });


        }

        private void GenerateProtocolIDActivity_ExecuteCode(object sender, EventArgs e)
        {

            SPListItem item = this.workflowProperties.Item;

            string protocolID = BuildProtocolID(item);

            if (!string.IsNullOrEmpty(protocolID))
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    try
                    {
                        using (SPSite site = new SPSite(item.Web.Url))
                        {
                            site.AllowUnsafeUpdates = true;

                            using (SPWeb web = site.OpenWeb())
                            {

                                web.AllowUnsafeUpdates = true;

                                SPListItem itemToUpdate = web.Lists[this.workflowProperties.Item.ParentList.ID].GetItemById(this.workflowProperties.Item.ID);

                                itemToUpdate[itemToUpdate.ParentList.Fields.GetFieldByInternalName("ProtocolID").Id] = protocolID;
                                itemToUpdate.UpdateOverwriteVersion();

                            }

                        }
                    }
                    catch (Exception codeException)
                    {
                        WriteError(codeException);
                    }

                });


            }
        }



        private string BuildProtocolID(SPListItem item)
        {
            string protocolID = "";


            // Get the forumula for the list.

            SPList configList = item.Web.GetList(string.Format("{0}/Lists/{1}", item.Web.ServerRelativeUrl, "LibraryConfiguration"));

            foreach (SPListItem configItem in configList.Items)
            {

                if (configItem["ListName"].ToString() == item.ParentList.Title)
                {






                    if (configItem[configItem.ParentList.Fields.GetFieldByInternalName("Formula").Id] != null)
                    {

                        string formula = configItem[configItem.ParentList.Fields.GetFieldByInternalName("Formula").Id].ToString();

                        protocolID = formula;

                        int startPos = 0;
                        int endPos = 0;
                        string formulaString = "";




                        #region Replace "AUTOID" token - use the ID to avoid duplicate ids
                        try
                        {
                            if (protocolID.Contains("AUTOID"))
                            {


                                int id = 0;

                                try
                                {

                                    // Get any offset so we can start the number schema from any position
                                    id = int.Parse(configItem[configItem.ParentList.Fields.GetFieldByInternalName("IDOffset").Id].ToString());
                                }
                                catch { ;}


                                startPos = protocolID.IndexOf("AUTOID[");
                                endPos = protocolID.IndexOf("]", startPos + 1);

                                formulaString = protocolID.Substring(startPos, endPos - startPos + 1);

                                string padLen = formulaString.Replace("AUTOID[", "").Replace("]", "");

                                // Insert the replacement string

                                id = id + item.ID;

                                protocolID = protocolID.Replace(formulaString, id.ToString().PadLeft(int.Parse(padLen), '0'));
                            }
                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }


                        #endregion

                        #region Replace "DATE" token
                        try
                        {
                            if (protocolID.Contains("DATE"))
                            {

                                startPos = protocolID.IndexOf("DATE[");
                                endPos = protocolID.IndexOf("]", startPos + 1);

                                formulaString = protocolID.Substring(startPos, endPos - startPos + 1);

                                string dateFormatString = formulaString.Replace("DATE[", "").Replace("]", "");


                                // Insert the replacement string
                                protocolID = protocolID.Replace(formulaString, DateTime.Today.ToString(dateFormatString));

                            }
                        }
                        catch (Exception codeException)
                        {
                            WriteError(codeException);
                        }

                        #endregion

                    }

                    break;
                }


            }


            return protocolID;
        }

        private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
        {

        }





    }
}
